using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.IO;
using System.Windows.Forms;
using GraphAlgsPresentation.Core;
using GraphAlgsPresentation.ScriptLibrary;

namespace GraphAlgsPresentation.ScriptPlayer
{
    /// <summary>
    /// Represents a user control of ScriptPlayer
    /// </summary>
    public partial class ScriptPlayer : UserControl
    {
        private Script script;
        private int stepId;
        private int commandId;
        private StringBuilder s;

        #region Initialize

        /// <summary>
        /// Initializes a new instance of the <see cref="ScriptPlayer"/> class.
        /// </summary>
        public ScriptPlayer()
        {            
            InitializeComponent();
            stepId = 0;
            commandId = 0;
            btnPrevious.Enabled = false;
            btnNext.Enabled = false;
            gp.Alarm += new AlarmEventHandler(OnAlarm);
            s = new StringBuilder();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the script.
        /// </summary>
        /// <value>The script.</value>
        public Script Script
        {
            get { return script; }
            set { script = value; }
        }

        #endregion

        #region Toolbar methods

        /// <summary>
        /// Handles the Click event of the btnOpen control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnOpen_Click(object sender, EventArgs e)
        {
            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.CheckPathExists = true;
            openDialog.DefaultExt = "xml";
            openDialog.Filter = "XML Files | *.xml";
            if (openDialog.ShowDialog() == DialogResult.OK)
            {
                LoadScript(openDialog.FileName);
            }
        }

        /// <summary>
        /// Loads the script.
        /// </summary>
        /// <param name="FileName">Name of the file.</param>
        public void LoadScript(string FileName)
        {
            StreamReader fi = new StreamReader(FileName);
            comment.Clear();
            s.Remove(0, s.Length);
            s.Append(fi.ReadToEnd());
            fi.Close();
            Script = Script.Deserialize(new StringReader(s.ToString()));
            Script.Context.CommentControl = comment;
            gp.LayoutContext = this.Script.Context.LayoutContext;
            gp.Draw();
            CheckFirstStep();
            stepId = 0;
            commandId = 0;
            btnNext.Enabled = true;
            btnPrevious.Enabled = false;
        }

        /// <summary>
        /// Handles the Click event of the btnExit control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// Checks the first step.
        /// </summary>
        private void CheckFirstStep()
        {
            foreach (Command cmd in Script.Commands[0])
            {
                string cmdName = cmd.GetType().ToString();
                if (!(cmdName.Contains("Text") && !cmdName.Contains("Vertex") && !cmdName.Contains("Edge")))
                    return;
            }
            foreach (Command cmd in Script.Commands[0])
                cmd.Run();
            Script.Commands.RemoveAt(0);
        }

        /// <summary>
        /// Handles the Click event of the btnRefresh control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            if (s.Length == 0) return;
            this.Script = Script.Deserialize(new StringReader(s.ToString()));
            comment.Clear();
            Script.Context.CommentControl = comment;
            gp.LayoutContext = this.Script.Context.LayoutContext;
            gp.Draw();
            CheckFirstStep();
            btnPrevious.Enabled = false;
            btnNext.Enabled = true;
            stepId = 0;
            commandId = 0;
        }

        /// <summary>
        /// Handles the Click event of the btnPrevious control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnPrevious_Click(object sender, EventArgs e)
        {
            stepId--;
            for (int i = Script.Commands[stepId].Count - 1; i >= 0; i--)
            {
                Command command = Script.Commands[stepId][i];
                command.Undo();
            }
            btnNext.Enabled = true;
            if (stepId == 0) btnPrevious.Enabled = false;
            gp.Draw();
            /*
            this.Script = Script.Deserialize(new StringReader(s.ToString()));
            comment.Clear();
            Script.Context.CommentControl = comment;
            gp.LayoutContext = this.Script.Context.LayoutContext;
            CheckFirstStep();
            for (int i = 0; i < stepId - 1; i++)
            {
                foreach (Command command in Script.Commands[i])
                    if (command is Delay == false) command.Run();
            }
            btnNext.Enabled = true;
            stepId--;
            if (stepId == 0) btnPrevious.Enabled = false;
            gp.Draw();
            */
        }

        /// <summary>
        /// Handles the Click event of the btnNext control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnNext_Click(object sender, EventArgs e)
        {
            if (stepId >= Script.Commands.Count) return;
            if (commandId != 0)
            {
                for (int i = commandId; i < Script.Commands[stepId].Count; i++) Script.Commands[stepId][i].Run();
                gp.Draw();
                stepId++;
            }
            btnPrevious.Enabled = false;
            if (stepId == Script.Commands.Count - 1) btnNext.Enabled = false;
            Script.Context.Update();
            commandId = 0;
            gp.Draw(true);
        }

        /// <summary>
        /// Called when [alarm].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="GraphAlgsPresentation.Core.AlarmEventArgs"/> instance containing the event data.</param>
        private void OnAlarm(object sender, AlarmEventArgs e)
        {
            if (stepId >= Script.Commands.Count) return;
            if (commandId == Script.Commands[stepId].Count)
            {
                commandId = 0;
                stepId++;
                btnPrevious.Enabled = true;
                if (stepId == Script.Commands.Count) btnNext.Enabled = false;
                return;
            }
            Script.Context.Update();
            Command currentCmd = Script.Commands[stepId][commandId];
            currentCmd.Run();
            commandId++;
            EffectManager.GetDrawingClass(currentCmd.Effect).Draw(gp);
        }
        #endregion
    }
}
